// Morgan + Winston 日志系统中文封装
const morgan = require('morgan');
const winston = require('winston');
const fs = require('fs');
const path = require('path');

// 默认日志配置
const 默认配置 = {
  日志级别: 'info',
  日志文件: path.join(process.cwd(), 'logs', 'app.log'),
  错误日志文件: path.join(process.cwd(), 'logs', 'error.log'),
  日期格式: 'YYYY-MM-DD HH:mm:ss.SSS'
};

/**
 * 创建Winston日志记录器
 * @param {Object} 配置 - 日志配置选项
 * @returns {Object} Winston日志记录器实例
 */
function 创建日志记录器(配置 = {}) {
  // 合并配置
  const 最终配置 = { ...默认配置, ...配置 };
  
  // 确保日志目录存在
  const 日志目录 = path.dirname(最终配置.日志文件);
  if (!fs.existsSync(日志目录)) {
    fs.mkdirSync(日志目录, { recursive: true });
  }
  
  // 创建日志格式
  const 日志格式 = winston.format.combine(
    winston.format.timestamp({ format: 最终配置.日期格式 }),
    winston.format.printf(({ timestamp, level, message, ...metadata }) => {
      let 日志消息 = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
      if (metadata && Object.keys(metadata).length > 0) {
        日志消息 += ` ${JSON.stringify(metadata)}`;
      }
      return 日志消息;
    })
  );
  
  // 创建日志记录器
  const 日志记录器 = winston.createLogger({
    level: 最终配置.日志级别,
    format: 日志格式,
    defaultMeta: { 应用名称: 最终配置.应用名称 || '应用' },
    transports: [
      // 控制台输出
      new winston.transports.Console({
        format: winston.format.combine(
          winston.format.colorize(),
          日志格式
        )
      }),
      // 普通日志文件
      new winston.transports.File({
        filename: 最终配置.日志文件,
        maxsize: 10485760, // 10MB
        maxFiles: 10,
        tailable: true
      })
    ]
  });
  
  // 添加错误日志传输
  if (最终配置.错误日志文件) {
    日志记录器.add(new winston.transports.File({
      filename: 最终配置.错误日志文件,
      level: 'error',
      maxsize: 10485760,
      maxFiles: 10,
      tailable: true
    }));
  }
  
  return 日志记录器;
}

/**
 * 创建Morgan中间件
 * @param {Object} 应用 - Express应用实例
 * @param {Object} 选项 - Morgan配置选项
 * @param {Object} 日志记录器 - 可选的Winston日志记录器
 */
function 创建HTTP日志中间件(应用, 选项 = {}, 日志记录器 = null) {
  const { 
    格式 = 'combined',
    输出流 = null
  } = 选项;
  
  if (日志记录器) {
    // 创建Morgan中间件，将日志输出到Winston
    const morganMiddleware = morgan(格式, {
      stream: {
        write: (消息) => {
          日志记录器.info(消息.trim());
        }
      }
    });
    
    应用.use(morganMiddleware);
  } else if (输出流) {
    // 使用自定义输出流
    应用.use(morgan(格式, { stream: 输出流 }));
  } else {
    // 默认输出到控制台
    应用.use(morgan(格式));
  }
}

/**
 * 记录调试日志
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string} 消息 - 日志消息
 * @param {Object} 元数据 - 附加的元数据
 */
function 记录调试信息(日志记录器, 消息, 元数据 = {}) {
  日志记录器.debug(消息, 元数据);
}

/**
 * 记录信息日志
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string} 消息 - 日志消息
 * @param {Object} 元数据 - 附加的元数据
 */
function 记录信息(日志记录器, 消息, 元数据 = {}) {
  日志记录器.info(消息, 元数据);
}

/**
 * 记录警告日志
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string} 消息 - 日志消息
 * @param {Object} 元数据 - 附加的元数据
 */
function 记录警告(日志记录器, 消息, 元数据 = {}) {
  日志记录器.warn(消息, 元数据);
}

/**
 * 记录错误日志
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string|Error} 错误 - 错误消息或错误对象
 * @param {Object} 元数据 - 附加的元数据
 */
function 记录错误(日志记录器, 错误, 元数据 = {}) {
  if (错误 instanceof Error) {
    日志记录器.error(错误.message, { 
      ...元数据,
      错误: 错误.message,
      堆栈: 错误.stack
    });
  } else {
    日志记录器.error(错误, 元数据);
  }
}

/**
 * 记录严重错误日志
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string|Error} 错误 - 错误消息或错误对象
 * @param {Object} 元数据 - 附加的元数据
 */
function 记录严重错误(日志记录器, 错误, 元数据 = {}) {
  if (错误 instanceof Error) {
    日志记录器.error(错误.message, { 
      ...元数据,
      错误: 错误.message,
      堆栈: 错误.stack,
      严重: true
    });
  } else {
    日志记录器.error(错误, { ...元数据, 严重: true });
  }
}

/**
 * 创建错误处理中间件
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @returns {Function} Express错误处理中间件
 */
function 创建错误处理中间件(日志记录器) {
  return function(错误, 请求, 响应, 下一个) {
    // 记录错误
    记录错误(日志记录器, 错误, {
      路径: 请求.path,
      方法: 请求.method,
      IP: 请求.ip,
      用户代理: 请求.headers['user-agent']
    });
    
    // 发送错误响应
    const 状态码 = 错误.status || 500;
    const 响应数据 = {
      错误: 状态码 === 500 ? '服务器内部错误' : 错误.message,
      状态码
    };
    
    // 开发环境下显示详细错误信息
    if (process.env.NODE_ENV !== 'production') {
      响应数据.详细信息 = 错误.stack;
    }
    
    响应.status(状态码).json(响应数据);
  };
}

/**
 * 创建带标签的日志函数
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string} 标签 - 日志标签
 * @returns {Object} 带标签的日志记录函数集
 */
function 创建带标签日志(日志记录器, 标签) {
  return {
    调试: (消息, 元数据 = {}) => 记录调试信息(日志记录器, `[${标签}] ${消息}`, 元数据),
    信息: (消息, 元数据 = {}) => 记录信息(日志记录器, `[${标签}] ${消息}`, 元数据),
    警告: (消息, 元数据 = {}) => 记录警告(日志记录器, `[${标签}] ${消息}`, 元数据),
    错误: (错误, 元数据 = {}) => 记录错误(日志记录器, `[${标签}] ${错误 instanceof Error ? 错误.message : 错误}`, 元数据),
    严重: (错误, 元数据 = {}) => 记录严重错误(日志记录器, `[${标签}] ${错误 instanceof Error ? 错误.message : 错误}`, 元数据)
  };
}

/**
 * 设置日志级别
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {string} 级别 - 日志级别（error, warn, info, debug, silly）
 */
function 设置日志级别(日志记录器, 级别) {
  日志记录器.level = 级别;
}

/**
 * 添加日志传输
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {Object} 传输 - Winston传输实例
 */
function 添加日志传输(日志记录器, 传输) {
  日志记录器.add(传输);
}

/**
 * 移除日志传输
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {Object} 传输 - Winston传输实例
 */
function 移除日志传输(日志记录器, 传输) {
  日志记录器.remove(传输);
}

/**
 * 创建文件日志传输
 * @param {string} 文件名 - 日志文件路径
 * @param {Object} 选项 - 传输选项
 * @returns {Object} Winston文件传输实例
 */
function 创建文件传输(文件名, 选项 = {}) {
  const 最终选项 = {
    filename: 文件名,
    maxsize: 10485760, // 10MB
    maxFiles: 10,
    tailable: true,
    ...选项
  };
  
  // 确保目录存在
  const 目录 = path.dirname(文件名);
  if (!fs.existsSync(目录)) {
    fs.mkdirSync(目录, { recursive: true });
  }
  
  return new winston.transports.File(最终选项);
}

/**
 * 创建控制台日志传输
 * @param {Object} 选项 - 传输选项
 * @returns {Object} Winston控制台传输实例
 */
function 创建控制台传输(选项 = {}) {
  const 最终选项 = {
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.timestamp(),
      winston.format.printf(({ timestamp, level, message }) => {
        return `[${timestamp}] [${level}] ${message}`;
      })
    ),
    ...选项
  };
  
  return new winston.transports.Console(最终选项);
}

/**
 * 记录API请求详细信息
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @param {Object} 请求 - Express请求对象
 * @param {Object} 响应 - Express响应对象
 * @param {number} 处理时间 - 请求处理时间（毫秒）
 */
function 记录API请求(日志记录器, 请求, 响应, 处理时间) {
  const 状态码 = 响应.statusCode;
  const 日志级别 = 状态码 >= 500 ? 'error' : 
                    状态码 >= 400 ? 'warn' : 'info';
  
  日志记录器[日志级别](`${请求.method} ${请求.originalUrl} ${状态码} ${处理时间}ms`, {
    方法: 请求.method,
    路径: 请求.originalUrl,
    状态码: 状态码,
    处理时间: 处理时间,
    IP: 请求.ip,
    用户代理: 请求.headers['user-agent'],
    内容类型: 请求.headers['content-type'],
    用户ID: 请求.user?.id || '未认证'
  });
}

/**
 * 创建API性能监控中间件
 * @param {Object} 日志记录器 - Winston日志记录器实例
 * @returns {Function} Express中间件
 */
function 创建性能监控中间件(日志记录器) {
  return function(req, res, next) {
    const 开始时间 = Date.now();
    
    // 当响应结束时记录请求信息
    res.on('finish', () => {
      const 处理时间 = Date.now() - 开始时间;
      
      // 只记录处理时间超过阈值的请求
      if (处理时间 > 500) { // 500ms
        记录警告(日志记录器, `请求处理缓慢: ${req.method} ${req.originalUrl}`, {
          处理时间: 处理时间,
          路径: req.originalUrl,
          方法: req.method
        });
      }
    });
    
    next();
  };
}

/**
 * 创建日志格式器
 * @param {string} 日期格式 - 时间戳格式
 * @param {boolean} 使用颜色 - 是否使用颜色
 * @returns {Object} Winston格式器
 */
function 创建日志格式(日期格式 = 'YYYY-MM-DD HH:mm:ss.SSS', 使用颜色 = false) {
  const 格式组件 = [
    winston.format.timestamp({ format: 日期格式 }),
    winston.format.printf(({ timestamp, level, message, ...metadata }) => {
      let 日志消息 = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
      if (metadata && Object.keys(metadata).length > 0) {
        日志消息 += ` ${JSON.stringify(metadata)}`;
      }
      return 日志消息;
    })
  ];
  
  if (使用颜色) {
    格式组件.unshift(winston.format.colorize());
  }
  
  return winston.format.combine(...格式组件);
}

/**
 * 创建一个完整的日志系统
 * @param {Object} 配置 - 日志系统配置
 * @returns {Object} 完整的日志系统对象
 */
function 创建日志系统(配置 = {}) {
  // 创建日志记录器
  const 日志记录器 = 创建日志记录器(配置);
  
  return {
    // 日志记录器实例
    记录器: 日志记录器,
    
    // 日志记录函数
    调试: (消息, 元数据) => 记录调试信息(日志记录器, 消息, 元数据),
    信息: (消息, 元数据) => 记录信息(日志记录器, 消息, 元数据),
    警告: (消息, 元数据) => 记录警告(日志记录器, 消息, 元数据),
    错误: (错误, 元数据) => 记录错误(日志记录器, 错误, 元数据),
    严重: (错误, 元数据) => 记录严重错误(日志记录器, 错误, 元数据),
    
    // 工具函数
    创建带标签日志: (标签) => 创建带标签日志(日志记录器, 标签),
    设置日志级别: (级别) => 设置日志级别(日志记录器, 级别),
    添加日志传输: (传输) => 添加日志传输(日志记录器, 传输),
    移除日志传输: (传输) => 移除日志传输(日志记录器, 传输),
    
    // Express中间件
    创建HTTP日志中间件: (应用, 选项) => 创建HTTP日志中间件(应用, 选项, 日志记录器),
    创建错误处理中间件: () => 创建错误处理中间件(日志记录器),
    创建性能监控中间件: () => 创建性能监控中间件(日志记录器),
    
    // 传输创建函数
    创建文件传输,
    创建控制台传输,
    
    // 格式创建函数
    创建日志格式
  };
}

module.exports = {
  // 核心函数
  创建日志记录器,
  创建日志系统,
  
  // 日志记录函数
  记录调试信息,
  记录信息,
  记录警告,
  记录错误,
  记录严重错误,
  记录API请求,
  
  // Express中间件
  创建HTTP日志中间件,
  创建错误处理中间件,
  创建性能监控中间件,
  
  // 工具函数
  创建带标签日志,
  设置日志级别,
  添加日志传输,
  移除日志传输,
  
  // 传输创建函数
  创建文件传输,
  创建控制台传输,
  
  // 格式创建函数
  创建日志格式,
  
  // 获取原始模块
  获取原始Morgan: () => morgan,
  获取原始Winston: () => winston,
  
  // 常量
  日志级别: {
    ERROR: 'error',
    WARN: 'warn',
    INFO: 'info',
    DEBUG: 'debug',
    SILLY: 'silly'
  }
};